package org.cybzacg.convert.converters.gather;

import org.cybzacg.convert.annotation.Converter;
import org.cybzacg.convert.context.ConversionContext;
import org.cybzacg.convert.core.AbstractTypeConverter;
import org.cybzacg.convert.enums.ConversionError;
import org.cybzacg.convert.enums.ConversionPriority;
import org.cybzacg.convert.enums.ConversionType;
import org.cybzacg.convert.exception.ConversionException;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Array;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * Map类型转换器
 * 支持各种Map类型之间的转换
 *
 * @author cybzacg.blog
 * @version 4.0
 * @since 3.0
 */
@Slf4j
@Converter(name = "MapConverter", priority = ConversionPriority.MEDIUM, description = "Map类型转换器，支持各种Map类型之间的转换", enabled = true, version = "4.0", author = "cybzacg.blog", supportedTypes = {
        Map.class }, tags = { "map", "container", "conversion" })
public class MapConverter extends AbstractTypeConverter {

    // Map类型实现类映射
    private static final Map<Class<?>, Class<?>> MAP_IMPLEMENTATIONS = new ConcurrentHashMap<>();

    static {
        MAP_IMPLEMENTATIONS.put(Map.class, HashMap.class);
        MAP_IMPLEMENTATIONS.put(SortedMap.class, TreeMap.class);
        MAP_IMPLEMENTATIONS.put(NavigableMap.class, TreeMap.class);
        MAP_IMPLEMENTATIONS.put(ConcurrentMap.class, ConcurrentHashMap.class);
    }

    public MapConverter() {
        super(ConversionPriority.MEDIUM);
        log.debug("MapConverter 初始化完成");
    }

    @Override
    protected ConversionType getConversionType() {
        return ConversionType.MAP;
    }

    @Override
    @SuppressWarnings("unchecked")
    protected <T> T doConvert(Object source, Class<T> targetType, T defaultValue, ConversionContext context)
            throws Exception {

        if (source == null) {
            return defaultValue;
        }

        // 如果已经是目标类型，直接返回
        if (targetType.isInstance(source)) {
            return (T) source;
        }

        // 转换为Map
        return (T) convertToMap(source, targetType, context);
    }

    /**
     * 将对象转换为Map
     */
    @SuppressWarnings("unchecked")
    protected <T> Map<Object, Object> convertToMap(Object source, Class<T> targetType, ConversionContext context)
            throws ConversionException {

        if (source == null) {
            return createEmptyMap(targetType);
        }

        // Map转Map
        if (source instanceof Map) {
            return convertMapToMap((Map<?, ?>) source, targetType, context);
        }

        // 数组转Map
        if (source.getClass().isArray()) {
            return convertArrayToMap(source, targetType, context);
        }

        // 集合转Map
        if (source instanceof Collection) {
            return convertCollectionToMap((Collection<?>) source, targetType, context);
        }

        // 字符串转Map
        if (source instanceof String) {
            return convertStringToMap((String) source, targetType, context);
        }

        // 对象转Map
        return convertObjectToMap(source, targetType, context);
    }

    /**
     * Map转Map
     */
    @SuppressWarnings("unchecked")
    protected <T> Map<Object, Object> convertMapToMap(Map<?, ?> source, Class<T> targetType, ConversionContext context)
            throws ConversionException {

        Map<Object, Object> targetMap = createEmptyMap(targetType);

        for (Map.Entry<?, ?> entry : source.entrySet()) {
            Object key = convertMapKey(entry.getKey(), context);
            Object value = convertMapValue(entry.getValue(), context);
            targetMap.put(key, value);
        }

        return targetMap;
    }

    /**
     * 数组转Map
     */
    @SuppressWarnings("unchecked")
    protected <T> Map<Object, Object> convertArrayToMap(Object array, Class<T> targetType, ConversionContext context)
            throws ConversionException {

        Map<Object, Object> targetMap = createEmptyMap(targetType);

        // 根据上下文属性决定转换方式
        String arrayConversionMode = context.getProperty("arrayConversionMode");
        if (arrayConversionMode == null) {
            arrayConversionMode = "index";
        }

        switch (arrayConversionMode.toLowerCase()) {
            case "pair":
                // 偶数索引为key，奇数索引为value
                convertArrayToMapByPair(array, targetMap, context);
                break;
            case "entry":
                // 数组元素为Map.Entry
                convertArrayToMapByEntry(array, targetMap, context);
                break;
            case "index":
            default:
                // 索引为key，元素为value
                convertArrayToMapByIndex(array, targetMap, context);
                break;
        }

        return targetMap;
    }

    /**
     * 集合转Map
     */
    @SuppressWarnings("unchecked")
    protected <T> Map<Object, Object> convertCollectionToMap(Collection<?> source, Class<T> targetType,
            ConversionContext context)
            throws ConversionException {

        Map<Object, Object> targetMap = createEmptyMap(targetType);

        // 根据上下文属性决定转换方式
        String collectionConversionMode = context.getProperty("collectionConversionMode");
        if (collectionConversionMode == null) {
            collectionConversionMode = "index";
        }

        switch (collectionConversionMode.toLowerCase()) {
            case "pair":
                // 偶数索引为key，奇数索引为value
                convertCollectionToMapByPair(source, targetMap, context);
                break;
            case "entry":
                // 集合元素为Map.Entry
                convertCollectionToMapByEntry(source, targetMap, context);
                break;
            case "index":
            default:
                // 索引为key，元素为value
                convertCollectionToMapByIndex(source, targetMap, context);
                break;
        }

        return targetMap;
    }

    /**
     * 字符串转Map
     */
    @SuppressWarnings("unchecked")
    protected <T> Map<Object, Object> convertStringToMap(String source, Class<T> targetType, ConversionContext context)
            throws ConversionException {

        if (source == null || source.trim().isEmpty()) {
            return createEmptyMap(targetType);
        }

        Map<Object, Object> targetMap = createEmptyMap(targetType);

        // 获取分隔符
        String entrySeparator = context.getProperty("entrySeparator");
        if (entrySeparator == null) {
            entrySeparator = ",";
        }

        String keyValueSeparator = context.getProperty("keyValueSeparator");
        if (keyValueSeparator == null) {
            keyValueSeparator = "=";
        }

        // 分割键值对
        String[] entries = source.split(entrySeparator.trim());

        for (String entry : entries) {
            String trimmed = entry.trim();
            if (!trimmed.isEmpty()) {
                String[] keyValue = trimmed.split(keyValueSeparator.trim(), 2);
                if (keyValue.length == 2) {
                    Object key = convertMapKey(keyValue[0].trim(), context);
                    Object value = convertMapValue(keyValue[1].trim(), context);
                    targetMap.put(key, value);
                } else if (keyValue.length == 1) {
                    // 只有key，value为空字符串
                    Object key = convertMapKey(keyValue[0].trim(), context);
                    targetMap.put(key, "");
                }
            }
        }

        return targetMap;
    }

    /**
     * 对象转Map
     */
    @SuppressWarnings("unchecked")
    protected <T> Map<Object, Object> convertObjectToMap(Object source, Class<T> targetType, ConversionContext context)
            throws ConversionException {

        Map<Object, Object> targetMap = createEmptyMap(targetType);

        // 尝试通过反射获取对象属性
        try {
            Class<?> clazz = source.getClass();
            java.lang.reflect.Field[] fields = clazz.getDeclaredFields();

            for (java.lang.reflect.Field field : fields) {
                field.setAccessible(true);
                Object value = field.get(source);
                targetMap.put(field.getName(), value);
            }

        } catch (Exception e) {
            // 反射失败，使用默认方式
            targetMap.put("value", source);
        }

        return targetMap;
    }

    /**
     * 按索引方式将数组转换为Map
     */
    protected void convertArrayToMapByIndex(Object array, Map<Object, Object> targetMap, ConversionContext context) {
        int length = Array.getLength(array);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(array, i);
            Object key = convertMapKey(i, context);
            Object value = convertMapValue(element, context);
            targetMap.put(key, value);
        }
    }

    /**
     * 按键值对方式将数组转换为Map
     */
    protected void convertArrayToMapByPair(Object array, Map<Object, Object> targetMap, ConversionContext context) {
        int length = Array.getLength(array);
        for (int i = 0; i < length - 1; i += 2) {
            Object key = Array.get(array, i);
            Object value = Array.get(array, i + 1);

            Object convertedKey = convertMapKey(key, context);
            Object convertedValue = convertMapValue(value, context);
            targetMap.put(convertedKey, convertedValue);
        }
    }

    /**
     * 按Entry方式将数组转换为Map
     */
    @SuppressWarnings("unchecked")
    protected void convertArrayToMapByEntry(Object array, Map<Object, Object> targetMap, ConversionContext context) {
        int length = Array.getLength(array);
        for (int i = 0; i < length; i++) {
            Object element = Array.get(array, i);
            if (element instanceof Map.Entry) {
                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) element;
                Object key = convertMapKey(entry.getKey(), context);
                Object value = convertMapValue(entry.getValue(), context);
                targetMap.put(key, value);
            }
        }
    }

    /**
     * 按索引方式将集合转换为Map
     */
    protected void convertCollectionToMapByIndex(Collection<?> source, Map<Object, Object> targetMap,
            ConversionContext context) {
        int index = 0;
        for (Object element : source) {
            Object key = convertMapKey(index, context);
            Object value = convertMapValue(element, context);
            targetMap.put(key, value);
            index++;
        }
    }

    /**
     * 按键值对方式将集合转换为Map
     */
    protected void convertCollectionToMapByPair(Collection<?> source, Map<Object, Object> targetMap,
            ConversionContext context) {
        List<?> list = new ArrayList<>(source);
        for (int i = 0; i < list.size() - 1; i += 2) {
            Object key = list.get(i);
            Object value = list.get(i + 1);

            Object convertedKey = convertMapKey(key, context);
            Object convertedValue = convertMapValue(value, context);
            targetMap.put(convertedKey, convertedValue);
        }
    }

    /**
     * 按Entry方式将集合转换为Map
     */
    @SuppressWarnings("unchecked")
    protected void convertCollectionToMapByEntry(Collection<?> source, Map<Object, Object> targetMap,
            ConversionContext context) {
        for (Object element : source) {
            if (element instanceof Map.Entry) {
                Map.Entry<?, ?> entry = (Map.Entry<?, ?>) element;
                Object key = convertMapKey(entry.getKey(), context);
                Object value = convertMapValue(entry.getValue(), context);
                targetMap.put(key, value);
            }
        }
    }

    /**
     * 转换Map的键
     */
    protected Object convertMapKey(Object key, ConversionContext context) {
        if (key == null) {
            return null;
        }

        // 键通常保持原样，或者转换为字符串
        return key.toString();
    }

    /**
     * 转换Map的值
     */
    protected Object convertMapValue(Object value, ConversionContext context) {
        if (value == null) {
            return null;
        }

        // 值保持原样
        return value;
    }

    /**
     * 创建空Map
     */
    @SuppressWarnings("unchecked")
    protected <T> Map<Object, Object> createEmptyMap(Class<T> targetType) throws ConversionException {

        try {
            // 如果是具体的Map实现类，直接实例化
            if (Map.class.isAssignableFrom(targetType) &&
                    !targetType.isInterface() &&
                    !java.lang.reflect.Modifier.isAbstract(targetType.getModifiers())) {
                return (Map<Object, Object>) targetType.getDeclaredConstructor().newInstance();
            }

            // 根据接口类型选择实现类
            Class<?> implementationClass = MAP_IMPLEMENTATIONS.get(targetType);
            if (implementationClass != null) {
                return (Map<Object, Object>) implementationClass.getDeclaredConstructor().newInstance();
            }

            // 默认使用HashMap
            return new HashMap<>();

        } catch (Exception e) {
            throw new ConversionException(ConversionError.CONVERSION_FAILED,
                    "无法创建Map实例: " + targetType.getSimpleName(), e);
        }
    }

    @Override
    public boolean supports(Class<?> targetType) {
        return getSupportedType().isAssignableFrom(targetType);
    }

    @Override
    public Class<?> getSupportedType() {
        return Map.class;
    }

    /**
     * 检查是否为Map类型
     *
     * @param clazz 类型
     * @return 是否为Map类型
     */
    public static boolean isMapType(Class<?> clazz) {
        return Map.class.isAssignableFrom(clazz);
    }

    /**
     * 创建指定类型的Map
     *
     * @param <T>      Map类型
     * @param mapClass Map类型
     * @return Map实例
     * @throws ConversionException 创建失败时抛出
     */
    @SuppressWarnings("unchecked")
    public static <T extends Map<?, ?>> T createMap(Class<T> mapClass) throws ConversionException {
        try {
            if (mapClass.isInterface() || java.lang.reflect.Modifier.isAbstract(mapClass.getModifiers())) {
                Class<?> implementationClass = MAP_IMPLEMENTATIONS.get(mapClass);
                if (implementationClass != null) {
                    return (T) implementationClass.getDeclaredConstructor().newInstance();
                }
                return (T) new HashMap<>();
            }
            return mapClass.getDeclaredConstructor().newInstance();
        } catch (Exception e) {
            throw new ConversionException(ConversionError.CONVERSION_FAILED,
                    "无法创建Map实例: " + mapClass.getSimpleName(), e);
        }
    }

    /**
     * 安全的Map转换
     *
     * @param <T>        目标类型
     * @param source     源对象
     * @param targetType 目标类型
     * @return 转换结果
     */
    @SuppressWarnings("unchecked")
    public static <T> T convertSafely(Object source, Class<T> targetType) {
        if (source == null) {
            return null;
        }

        if (targetType.isInstance(source)) {
            return (T) source;
        }

        MapConverter converter = new MapConverter();
        try {
            return (T) converter.convertToMap(source, targetType, null);
        } catch (Exception e) {
            throw new ConversionException(ConversionError.CONVERSION_FAILED,
                    "安全Map转换失败: " + source + " -> " + targetType, e);
        }
    }
}
